package reflact;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 反射练习
 * @Author Antony
 * @Since 2017/12/1 15:24
 */
public class BeanUtil {

    /**
     * 利用反射,将target中的属性从source中复制, 如果没有则为空
     * @param source
     * @param target
     * @return
     */
    public static void copyProperties(Object source, Object target){
        Field[] fields = target.getClass().getDeclaredFields();
        for(Field f : fields){
            String fieldName = f.getName();
            Class fieldClazz = f.getType();
            try {
                Object fieldValue = getPropertyObject(source, fieldName);
                setProperty(target, fieldValue, fieldClazz, fieldName);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        return ;
    }


    /**
     * 获取bean的name属性.使用 convert 的 convertToString() 返回
     * @param bean
     * @param name
     * @param converter 自定义的toString converter. 如果为null,则使用默认对象的toString()
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static String getProperty(Object bean, String name, BeanValueConverter<Object, String> converter) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Object o = getPropertyObject(bean, name);
        if(converter == null){
            return o.toString();
        }
        return converter.convertToString(o);
    }


    /**
     * 获取bean的name属性.使用默认的 toString() 返回
     * @param bean
     * @param name
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static String getProperty(Object bean, String name) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        return getProperty(bean, name, null);
    }

    /**
     * 返回 Object 格式 bean的name属性
     * @param bean
     * @param name
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static Object getPropertyObject(Object bean, String name) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        if(bean == null){
            throw new IllegalArgumentException("No bean specified");
        }
        if(name == null){
            throw new IllegalArgumentException("No name specified for bean class '"+bean.getClass()+"'");
        }
        String methodName = "get" + name.substring(0,1).toUpperCase() + name.substring(1,name.length());
        Method method = bean.getClass().getMethod(methodName);
        Object o =method.invoke(bean,null);
        return o;
    }


    /**
     * 给Bean设置值
     * @param bean 需要赋值的bean
     * @param param 赋值参数的value
     * @param paramType 参数类型
     * @param paramName 参数名
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static Object setProperty(Object bean, Object param, Class paramType, String paramName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        if(bean == null){
            throw new IllegalArgumentException("no bean specified");
        }
        if(paramType == null){
            throw new IllegalArgumentException("no type specified");
        }
        if(paramName == null){
            throw new IllegalArgumentException("No name specified for bean class '"+bean.getClass()+"'");
        }
        String setterMethodName = "set" + paramName.substring(0,1).toUpperCase() + paramName.substring(1,paramName.length());
        Method setterMethod = bean.getClass().getDeclaredMethod(setterMethodName, paramType);
        setterMethod.invoke(bean, param);
        return bean;
    }

}
